<!-- tab组件: <me-tabs v-model="tabIndex" :tabs="tabs" @change="tabChange"></me-tabs> -->
<template>
    <view
        class="me-tabs"
        :class="{ 'tabs-fixed': fixed }"
        :style="{
            height: tabHeightVal,
            top: topFixed,
            'margin-top': topMargin,
        }"
    >
        <scroll-view
            v-if="tabs.length"
            :id="viewId"
            :scroll-left="scrollLeft"
            scroll-x
            scroll-with-animation
            :scroll-animation-duration="300"
        >
            <view class="tabs-item" :class="{ 'tabs-flex': !isScroll, 'tabs-scroll': isScroll }">
                <!-- tab -->
                <view
                    class="tab-item"
                    :style="{
                        width: tabWidthVal,
                        height: tabHeightVal,
                        'line-height': tabHeightVal,
                    }"
                    v-for="(tab, i) in tabs"
                    :class="{ active: value === i }"
                    :key="i"
                    @click="tabClick(i)"
                >
                    {{ getTabName(tab) }}
                </view>
                <!-- 下划线 -->
                <view class="tabs-line" :style="{ left: lineLeft }"></view>
            </view>
        </scroll-view>
    </view>
</template>

<script>
export default {
    props: {
        tabs: {
            // 支持格式: ['全部', '待付款'] 或 [{name:'全部'}, {name:'待付款'}]
            type: Array,
            default() {
                return [];
            },
        },
        nameKey: {
            // 取name的字段
            type: String,
            default: "name",
        },
        value: {
            // 当前显示的下标 (使用v-model语法糖: 1.props需为value; 2.需回调input事件)
            type: [String, Number],
            default: 0,
        },
        fixed: Boolean, // 是否悬浮,默认false
        tabWidth: Number, // 每个tab的宽度,默认不设置值,为flex平均分配; 如果指定宽度,则不使用flex,每个tab居左,超过则水平滑动(单位默认rpx)
        height: {
            // 高度,单位rpx
            type: Number,
            default: 64,
        },
        top: {
            // 顶部偏移的距离,默认单位rpx (当fixed=true时,已加上windowTop)
            type: Number,
            default: 0,
        },
    },
    data() {
        return {
            viewId: "id_" + Math.random().toString(36).substr(2, 16),
            scrollLeft: 0,
            windowWidth: 0,
            windowTop: 0,
        };
    },
    computed: {
        isScroll() {
            return this.tabWidth && this.tabs.length; // 指定了tabWidth的宽度,则支持水平滑动
        },
        tabHeightPx() {
            return uni.upx2px(this.height);
        },
        tabHeightVal() {
            return this.tabHeightPx + "px";
        },
        tabWidthPx() {
            return uni.upx2px(this.tabWidth);
        },
        tabWidthVal() {
            return this.isScroll ? this.tabWidthPx + "px" : "";
        },
        lineLeft() {
            if (this.isScroll) {
                return this.tabWidthPx * this.value + this.tabWidthPx / 2 + "px"; // 需转为px (用rpx的话iOS真机显示有误差)
            } else {
                return (
                    (100 / this.tabs.length) * (this.value + 1) - 100 / (this.tabs.length * 2) + "%"
                );
            }
        },
        topFixed() {
            return this.fixed ? this.windowTop + uni.upx2px(this.top) + "px" : 0;
        },
        topMargin() {
            return this.fixed ? 0 : this.top + "rpx";
        },
    },
    watch: {
        tabs() {
            this.warpWidth = null; // 重新计算容器宽度
            this.scrollCenter(); // 水平滚动到中间
        },
        value() {
            this.scrollCenter(); // 水平滚动到中间
        },
    },
    created() {
        let sys = this.$store.state.systemInfo;
        this.windowWidth = sys.windowWidth;
        this.windowTop = sys.windowTop;
    },
    mounted() {
        this.scrollCenter(); // 滚动到当前下标
    },
    methods: {
        getTabName(tab) {
            return typeof tab === "object" ? tab[this.nameKey] : tab;
        },
        tabClick(i) {
            if (this.value != i) {
                this.$emit("input", i);
                this.$emit("change", i);
            }
        },
        async scrollCenter() {
            if (!this.isScroll) return;
            if (!this.warpWidth) {
                // tabs容器的宽度
                let rect = await this.initWarpRect();
                this.warpWidth = rect ? rect.width : this.windowWidth; // 某些情况下取不到宽度,暂时取屏幕宽度
            }
            let tabLeft = this.tabWidthPx * this.value + this.tabWidthPx / 2; // 当前tab中心点到左边的距离
            let diff = tabLeft - this.warpWidth / 2; // 如果超过tabs容器的一半,则滚动差值
            this.scrollLeft = diff;
            // #ifdef MP-TOUTIAO
            this.scrollTimer && clearTimeout(this.scrollTimer);
            this.scrollTimer = setTimeout(() => {
                // 字节跳动小程序,需延时再次设置scrollLeft,否则tab切换跨度较大时不生效
                this.scrollLeft = Math.ceil(diff);
            }, 400);
            // #endif
        },
        initWarpRect() {
            return new Promise((resolve) => {
                setTimeout(() => {
                    // 延时确保dom已渲染, 不使用$nextclick
                    let query = uni.createSelectorQuery();
                    // #ifndef MP-ALIPAY
                    query = query.in(this); // 支付宝小程序不支持in(this),而字节跳动小程序必须写in(this), 否则都取不到值
                    // #endif
                    query
                        .select("#" + this.viewId)
                        .boundingClientRect((data) => {
                            resolve(data);
                        })
                        .exec();
                }, 20);
            });
        },
    },
};
</script>

<style lang="scss">
.me-tabs {
    position: relative;
    font-size: 24rpx;
    background-color: #fff;
    border-bottom: 1rpx solid #eee;
    box-sizing: border-box;
    overflow-y: hidden;
    background-color: #fff;
    &.tabs-fixed {
        z-index: 990;
        position: fixed;
        left: 0;
        width: 100%;
    }

    .tabs-item {
        position: relative;
        white-space: nowrap;
        padding-bottom: 30rpx; // 撑开高度,再配合me-tabs的overflow-y: hidden,以达到隐藏滚动条的目的
        box-sizing: border-box;
        .tab-item {
            position: relative;
            text-align: center;
            box-sizing: border-box;
            &.active {
                font-weight: bold;
                color: red;
            }
        }
    }

    // 平分的方式显示item
    .tabs-flex {
        display: flex;
        .tab-item {
            flex: 1;
        }
    }
    // 居左显示item,支持水平滑动
    .tabs-scroll {
        .tab-item {
            display: inline-block;
        }
    }

    // 选中tab的线
    .tabs-line {
        z-index: 1;
        position: absolute;
        bottom: 30rpx; // 至少与.tabs-item的padding-bottom一致,才能保证在底部边缘
        width: 50rpx;
        height: 6rpx;
        transform: translateX(-50%);
        border-radius: 4rpx;
        transition: left 0.3s;
        background: red;
    }
}
</style>
